﻿using System;
using System.Collections.Generic;
using AlgorytmyGenetyczne;
using AlgorytmyGenetyczne.Algorytmy;
using AlgorytmyGenetyczne.Kodowania;
using AlgorytmyGenetyczne.Operatory;

namespace ProjektDoTestowania
{
    class Program
    {
        static void Main(string[] args)
        {
            //TestKodowaniaBinarnego();
            //TestKrzyzowaniaOsobnikow();
            //TestKrzyzowaniaOsobnikowZKodowaniem();
            //TestMutacji();
            //TestKodowaniaGraya();
            //TestObliczaniaWartosciFunkcji();
            //TestKrzyzowaniaPopulacji();
            //TestMutacji();
            //TestKodowaniaGraya();
            TestSelekcji();

            System.Console.ReadKey();
        }

        static void TestKodowaniaBinarnego()
        {
            System.Console.WriteLine("TestKodowanaBinarnego");
            KodowanieBinarne kodowanie = new KodowanieBinarne(6, 0, 1);
            double wartoscDoZakodowania = 0.637197;
            double wartoscDoZakodowania2 = 0.231977;
            Genotyp genotyp = kodowanie.koduj(wartoscDoZakodowania)+kodowanie.koduj(wartoscDoZakodowania2);
            double wartoscZdekodowana = (double)kodowanie.dekoduj(genotyp.fragmentGenotypu(0, kodowanie.IloscBitow-1));
            double wartoscZdekodowana2 =
                (double) kodowanie.dekoduj(genotyp.fragmentGenotypu(kodowanie.IloscBitow, genotyp.Length-1));

            System.Console.WriteLine(wartoscDoZakodowania);
            System.Console.WriteLine(wartoscDoZakodowania2);
            System.Console.WriteLine(genotyp);
            System.Console.WriteLine(wartoscZdekodowana);
            System.Console.WriteLine(wartoscZdekodowana2);

            kodowanie = new KodowanieBinarne(6, 0, 1);
            wartoscDoZakodowania = 0.637197;
            genotyp = kodowanie.koduj(wartoscDoZakodowania);
            genotyp[17] = !genotyp[17];
            wartoscZdekodowana = (double)kodowanie.dekoduj(genotyp);

            System.Console.WriteLine(wartoscDoZakodowania);
            System.Console.WriteLine(genotyp);
            System.Console.WriteLine(wartoscZdekodowana);

            kodowanie = new KodowanieBinarne(1, 4, 8);
            wartoscDoZakodowania = 7;
            genotyp = kodowanie.koduj(wartoscDoZakodowania);
            wartoscZdekodowana = (double)kodowanie.dekoduj(genotyp);

            System.Console.WriteLine(wartoscDoZakodowania);
            System.Console.WriteLine(genotyp);
            System.Console.WriteLine(wartoscZdekodowana);
        }

        static void TestKodowaniaGraya()
        {
            System.Console.WriteLine("TestKodowanaGraya");
            KodowanieGraya kodowanie = new KodowanieGraya(6, -1, 2);
            double wartoscDoZakodowania = 0.637197;
            double wartoscDoZakodowania2 = 1.0;
            Genotyp genotyp = kodowanie.koduj(wartoscDoZakodowania) + kodowanie.koduj(wartoscDoZakodowania2);
            double wartoscZdekodowana = (double)kodowanie.dekoduj(genotyp.fragmentGenotypu(0, kodowanie.IloscBitow - 1));
            double wartoscZdekodowana2 =
                (double)kodowanie.dekoduj(genotyp.fragmentGenotypu(kodowanie.IloscBitow, genotyp.Length - 1));

            System.Console.WriteLine(wartoscDoZakodowania);
            System.Console.WriteLine(wartoscDoZakodowania2);
            System.Console.WriteLine(genotyp);
            System.Console.WriteLine(wartoscZdekodowana);
            System.Console.WriteLine(wartoscZdekodowana2);
            System.Console.WriteLine();

            kodowanie = new KodowanieGraya(6, 0, 1);
            wartoscDoZakodowania = 0.637197;
            genotyp = kodowanie.koduj(wartoscDoZakodowania);
            genotyp[17] = !genotyp[17];
            wartoscZdekodowana = (double)kodowanie.dekoduj(genotyp);

            System.Console.WriteLine(wartoscDoZakodowania);
            System.Console.WriteLine(genotyp);
            System.Console.WriteLine(wartoscZdekodowana);

            System.Console.WriteLine(wartoscDoZakodowania);
            System.Console.WriteLine(genotyp);
            System.Console.WriteLine(wartoscZdekodowana);

            kodowanie = new KodowanieGraya(1, 4, 8);
            wartoscDoZakodowania = 7;
            genotyp = kodowanie.koduj(wartoscDoZakodowania);
            wartoscZdekodowana = (double)kodowanie.dekoduj(genotyp);

            System.Console.WriteLine(wartoscDoZakodowania);
            System.Console.WriteLine(genotyp);
            System.Console.WriteLine(wartoscZdekodowana);
        }

        static void TestKrzyzowaniaOsobnikow()
        {
            System.Console.WriteLine("\n\n-----------------------------\nTEST-KRZYZOWANIE-OSOBNIKOW-BEZ-KODOWANIA");
            Krzyzowanie krzyzowanie = new Krzyzowanie(0.25, 1);
            Osobnik rodzic1 = new Osobnik();
            Osobnik rodzic2 = new Osobnik();

            bool[] geny1 = { true, false, false, true, true, true, false, false, true, false, true, false };
            rodzic1.Genotyp.Geny = geny1;
            System.Console.WriteLine("Rodzic1   = " + rodzic1.Genotyp.wyswietlNieodwrocony());

            bool[] geny2 = { true, true, false, false, false, false, true, true, true, true, false, false };
            rodzic2.Genotyp.Geny = geny2;
            System.Console.WriteLine("Rodzic2   = " + rodzic2.Genotyp.wyswietlNieodwrocony());

            Osobnik[] dzieci = krzyzowanie.krzyzujOsobnikow(rodzic1, rodzic2);
            for (int i = 0; i < dzieci.Length; i++)
            {
                System.Console.WriteLine("Dziecko" + i + 1 + " = " + dzieci[i].Genotyp.wyswietlNieodwrocony());
            }

        }

        static void TestKrzyzowaniaPopulacji()
        {
            System.Console.WriteLine("\n\n-----------------------------\nTEST-KRZYZOWANIA-POPULACJI");
            AbstractKodowanie kodowanie = new KodowanieGraya(6, 0, 1);
            int ILOSC_OSOBNIKOW = 10;
            int DLUGOSC_GENOTYPU = 10;
            Random random = new Random();
            Krzyzowanie krzyzowanie = new Krzyzowanie(0.25, 5);
            Populacja populacja = new Populacja();

            //GENEROWANIE POPULACJI
            bool[] geny = new bool[DLUGOSC_GENOTYPU];
            for(int i=0; i<ILOSC_OSOBNIKOW; i++)
            {
                Osobnik rodzic = new Osobnik();
                rodzic.Genotyp = kodowanie.koduj(random.NextDouble());
                System.Console.WriteLine("Rodzic "+(i+1)+" = " + rodzic.Genotyp);
                populacja.Osobnicy.Add(rodzic);
            }
            System.Console.WriteLine("\nPOPULACJA POCZATKOWA");
            foreach (Osobnik osobnik in populacja.Osobnicy)
            {
                System.Console.WriteLine(kodowanie.dekoduj(osobnik.Genotyp));
            }
            System.Console.WriteLine("\nROZPOCZYNAM KRZYZOWANIE");
            krzyzowanie.wykonaj(populacja);
            System.Console.WriteLine("ZAKONCZONO KRZYZOWANIE\n");

            for (int i = 0; i < populacja.Osobnicy.Count; i++)
            {
                System.Console.WriteLine("Osobnik " + (i + 1) + " = " + populacja.Osobnicy[i].Genotyp); 
            }

            System.Console.WriteLine("\nPOPULACJA KONCOWA");
            foreach (Osobnik osobnik in populacja.Osobnicy)
            {
                System.Console.WriteLine(kodowanie.dekoduj(osobnik.Genotyp));
            }
        }

        static void TestKrzyzowaniaOsobnikowZKodowaniem()
        {
            System.Console.WriteLine("\n\n-----------------------------\nTEST-KRZYZOWANIE-OSOBNIKOW-Z-KODOWANIEM");
            KodowanieBinarne kodowanie = new KodowanieBinarne(6, -1, 2);
            Krzyzowanie krzyzowanie = new Krzyzowanie(0.25, 1);
            Random random = new Random();
            krzyzowanie.IloscPunktowKrzyzowania = 5;

            double wartosc1 = random.NextDouble();
            double wartosc2 = random.NextDouble();
            Genotyp genotyp1 = kodowanie.koduj(wartosc1);
            Genotyp genotyp2 = kodowanie.koduj(wartosc2);
            Osobnik rodzic1 = new Osobnik();
            Osobnik rodzic2 = new Osobnik();
            rodzic1.Genotyp = genotyp1;
            rodzic2.Genotyp = genotyp2;
            System.Console.WriteLine("Rodzic1 = " + wartosc1 + "\n" + genotyp1);
            System.Console.WriteLine("\n\nRodzic2 = " + wartosc2 + "\n" + genotyp2);
            Osobnik[] dzieci = krzyzowanie.krzyzujOsobnikow(rodzic1, rodzic2);
            for (int i = 0; i < dzieci.Length; i++)
            {
                System.Console.WriteLine("\n\nDziecko" + (i + 1) + " = " + (double)kodowanie.dekoduj(dzieci[i].Genotyp) + "\n" + dzieci[i].Genotyp);

            }
        }

        static void TestMutacji()
        {
            System.Console.WriteLine("\n\n-----------------------------\nTEST-MUTACJI");
            Mutacja mutacja = new Mutacja(0.01);
            Populacja populacja = new Populacja();
            Osobnik rodzic1 = new Osobnik();
            bool[] geny1 = { true, true, true, true, true, true, true, true, true, true, true, true };
            rodzic1.Genotyp.Geny = geny1;
            System.Console.WriteLine("Rodzic1 = " + rodzic1.Genotyp.wyswietlNieodwrocony());
            populacja.Osobnicy.Add(rodzic1);
            mutacja.wykonaj(populacja);
            System.Console.WriteLine("Rodzic1 = " + rodzic1.Genotyp.wyswietlNieodwrocony());
        }

        static void TestObliczaniaWartosciFunkcji()
        {
            System.Console.WriteLine("\n\n-----------------------------\nTEST-OBLICZANIA-WARTOSCI-FUNKCJI");
            IFunkcja funkcja = new Funkcja("y = pow(x1,2) + pow(x2,2)",2);
            System.Console.WriteLine("Wzor funkcji :: " + funkcja);
            double x1 = 2.0;
            double x2 = 3.0;
            double[] argumenty = {x1, x2};
            System.Console.WriteLine("TEST FUNKCJI :: dla argumentow x1 = " + x1 + "  ,  x2 = "+x2);
            System.Console.WriteLine("TEST FUNKCJI :: wynik = " + funkcja.wartosc(argumenty));
        }
        
        [Obsolete("Test można uruchomić tylko jeśli w PAG jest odpowiednie dekodowanie w funkcji oceny")]
        static void TestOcenyPrzystosowania()
        {
            System.Console.WriteLine("\n\n-----------------------------\nTEST-OCENY-PRZYSTOSOWANIA");
            
            int minDziedziny = -3;
            int maxDziedziny = 3;
            int WIELKOSC_POPULACJI = 10;
            AbstractKodowanie kodowanie = new KodowanieBinarne(3, minDziedziny, maxDziedziny);
            List<AbstractKodowanie> kodowania = new List<AbstractKodowanie>();
            kodowania.Add(kodowanie);
            PAG pag = new PAG(kodowania);
            pag.Funkcja = new Funkcja("y = pow(x1,3)", 1);
            Populacja populacja = new Populacja();
            Osobnik osobnik;
            Random random = new Random();

            for (int i = 0; i < WIELKOSC_POPULACJI; i++)
            {
                osobnik = new Osobnik();
                double wartosc = -3 + random.NextDouble() * 6;
                System.Console.WriteLine("Osobnik-arg " + (i + 1) + " = " + wartosc); 
                osobnik.Genotyp = kodowanie.koduj(wartosc);
                populacja.Osobnicy.Add(osobnik);
            }

            pag.ocena(populacja);

            for (int i = 0; i < populacja.Osobnicy.Count; i++)
            {
                System.Console.WriteLine("Osobnik-ocena " + (i + 1) + " = " + populacja.Osobnicy[i].Ocena); 
            }
        }

        [Obsolete("Test można uruchomić tylko jeśli w PAG jest odpowiednie dekodowanie w funkcji oceny")]
        static void TestSelekcji()
        {
            int minDziedziny = -3;
            int maxDziedziny = 3;
            int WIELKOSC_POPULACJI = 20;
            AbstractKodowanie kodowanie = new KodowanieBinarne(3, minDziedziny, maxDziedziny);
            SelekcjaRuletki selekcja = new SelekcjaRuletki();
            selekcja.Elitarnosc = false;
            //selekcja.WielkoscElity = 1;
            List<AbstractKodowanie> kodowania = new List<AbstractKodowanie>();
            kodowania.Add(kodowanie);
            PAG pag = new PAG(kodowania);
            pag.Funkcja = new Funkcja("y = pow(x1,3)", 1);
            Populacja populacja = new Populacja();
            Osobnik osobnik;
            Random random = new Random();
            System.Console.WriteLine("\n\nGenerowanie populacji-----------");
            for (int i = 0; i < WIELKOSC_POPULACJI; i++)
            {
                osobnik = new Osobnik();
                double wartosc = -3 + random.NextDouble() * 6;
                System.Console.WriteLine("Osobnik-arg " + (i + 1) + " = " + wartosc);
                osobnik.Genotyp = kodowanie.koduj(wartosc);
                populacja.Osobnicy.Add(osobnik);
            }

            pag.ocena(populacja);
            System.Console.WriteLine("\n\nWartosc przystosowania populacji-----------");
            for (int i = 0; i < populacja.Osobnicy.Count; i++)
            {
                System.Console.WriteLine("Osobnik-ocena " + (i + 1) + " = " + populacja.Osobnicy[i].Ocena);
            }

            System.Console.WriteLine("\nROZPOCZYNAM SELEKCJE");
            selekcja.wykonaj(populacja);
            System.Console.WriteLine("ZAKONCZONO SELEKCJE\n");

            
            System.Console.WriteLine("\n\nWyselekcjonowane osobniki-----------");
            Populacja wynikSelekcji = selekcja.WynikSelekcji;
            for (int i = 0; i < wynikSelekcji.Osobnicy.Count; i++)
            {
                System.Console.WriteLine("Osobnik-ocena " + (i + 1) + " = " + wynikSelekcji.Osobnicy[i].Ocena);
            }


        }
    }
}
